package com.atlin.project.utils.file;

import com.atlin.project.common.ErrorCode;
import com.atlin.project.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;


/**
 * 文件本地存储
 */
@Slf4j
public class LocalFileUtil {


    /**
     * 本地文件存储
     *
     * @param file       文件
     * @param fileName   文件名称
     * @param bucketName 存储目录
     */
    public static void save(File file, String fileName, String bucketName) {
        try {
            // fileName为空，说明要使用源文件名上传
            if (fileName == null) {
                fileName = RandomStringUtils.randomAlphanumeric(8) + System.currentTimeMillis();
                fileName = fileName.replaceAll(" ", "_");
            }
            File target = new File(bucketName);
            if (!target.exists() || !target.isDirectory()) {
                target.mkdirs();
            }

            Files.copy(file.toPath(), new File(bucketName + File.separator + fileName).toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件存储失败");
        }
    }

    /**
     * 文件获取
     *
     * @param fileName   文件名称
     * @param bucketName 目录
     * @param response   响应
     */
    public static void previewFile(String fileName, String bucketName, HttpServletResponse response) {
        byte[] fileByte = null;
        try (ServletOutputStream os = response.getOutputStream()) {
            File file = new File(bucketName + fileName);

            if (!file.exists()) {
                log.error("文件:[{}] 不存在", bucketName + fileName);
                throw new BusinessException(ErrorCode.NULL_ERROR, "文件不存在");
            }

            fileByte = Files.readAllBytes(file.toPath());
            os.write(fileByte);

        } catch (IOException e) {
            log.error("文件：{}读取失败", bucketName + fileName);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "图片读取失败");
        }
    }

    /**
     * 获取Base64编码后的图片文件
     *
     * @param fileName
     * @param bucketName
     * @return
     */
    public static String getBase64EncodingImageFile(String fileName, String bucketName) {
        byte[] fileByte = null;

        try {
            File file = new File(bucketName + fileName);
            if (!file.exists()) {
                log.error("文件:[{}] 不存在", bucketName + fileName);
                throw new BusinessException(ErrorCode.NULL_ERROR, "文件不存在");
            }
            fileByte = Files.readAllBytes(file.toPath());
        } catch (IOException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "图片读取失败");
        }

        return "data:image/png;base64," + Base64.encodeBase64String(fileByte);
    }


    /**
     * 文件下载
     *
     * @param fileName   文件名
     * @param bucketName 目录
     * @param response   相应
     */
    public static void download(String fileName, String bucketName, HttpServletResponse response) {
        try {
            setResponseHeaders(response, fileName);

            try (InputStream inputStream = getFileInputStream(bucketName, fileName);
                 OutputStream outputStream = response.getOutputStream()) {

                // 检查文件是否存在
                if (inputStream == null) {
                    handleFileNotFound(response, fileName);
                    return;
                }

                // 流式传输文件内容
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }

                outputStream.flush();

            } catch (IOException e) {
                handleDownloadError(response, e, fileName);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置响应头
     */
    private static void setResponseHeaders(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {
        // 设置内容类型为二进制流
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

        // 对文件名进行URL编码处理，防止中文乱码
        String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
                .replaceAll("\\+", "%20");

        // 设置下载头信息
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + encodedFileName + "\"; filename*=utf-8''" + encodedFileName);

        // 禁用缓存
        response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
        response.setHeader(HttpHeaders.PRAGMA, "no-cache");
        response.setHeader(HttpHeaders.EXPIRES, "0");
    }

    /**
     * 获取文件输入流 - 需要根据实际存储实现
     */
    private static InputStream getFileInputStream(String bucketName, String fileName) {
        // 这里需要根据您使用的存储服务实现具体的文件获取逻辑
        // 以下是几种常见存储服务的示例伪代码：

        // 1. 本地文件系统
        try {
            return new FileInputStream(bucketName + File.separator + fileName);
        } catch (FileNotFoundException e) {
            return null;
        }

        // 2. AWS S3
        // AmazonS3 s3Client = AmazonS3ClientBuilder.standard().build();
        // S3Object s3Object = s3Client.getObject(bucketName, fileName);
        // return s3Object.getObjectContent();

        // 3. 阿里云OSS
        // OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // OSSObject ossObject = ossClient.getObject(bucketName, fileName);
        // return ossObject.getObjectContent();

        // 4. 其他对象存储服务...

        // 暂时返回null，需要您根据实际情况实现
//        return null;
    }

    /**
     * 处理文件不存在的情况
     */
    private static void handleFileNotFound(HttpServletResponse response, String fileName) throws IOException {
        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        response.setContentType(MediaType.TEXT_PLAIN_VALUE);
        response.getWriter().write("File not found: " + fileName);
    }

    /**
     * 处理下载过程中的错误
     */
    private static void handleDownloadError(HttpServletResponse response, Exception e, String fileName) {
        try {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType(MediaType.TEXT_PLAIN_VALUE);
            response.getWriter().write("Error downloading file: " + fileName + ". Error: " + e.getMessage());
        } catch (IOException ex) {
            // 记录日志
            System.err.println("Error handling download error: " + ex.getMessage());
        }
    }


}
